﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.Caching;
using System.Text;

namespace Creative85.Framework.Utilities
{
    public class CacheUtility : ObjectCache
    {
        private static ObjectCache container = MemoryCache.Default;
        private static string generateCacheKey(string prefix, string key)
        {
            return string.Format("{0}-{1}" + (key == null ? string.Empty : "-{2}"), container.Name, prefix, key);
        }

        public string Prefix { get; private set; }

        public string GetFullKey(string key)
        {
            string fullKey = generateCacheKey(this.Prefix, key);
            return fullKey;
        }
        public string GetOriginalKey(string fullKey)
        {
            string prefix = this.GetFullKey(string.Empty);
            string key = fullKey.Substring(prefix.Length);
            return key;
        }

        public CacheUtility(string prefix)
        {
            this.Prefix = prefix;
        }

        public override object AddOrGetExisting(string key, object value, CacheItemPolicy policy, string regionName = null)
        {
            string fullKey = this.GetFullKey(key);
            return container.AddOrGetExisting(fullKey, value, policy, regionName);
        }

        public override CacheItem AddOrGetExisting(CacheItem value, CacheItemPolicy policy)
        {
            if (value != null)
            {
                value = new CacheItem(this.GetFullKey(value.Key), value.Value, value.RegionName);
            }
            CacheItem item = container.AddOrGetExisting(value, policy);
            if (item != null)
            {
                item = new CacheItem(this.GetOriginalKey(item.Key), item.Value, item.RegionName);
            }
            return item;
        }

        public override object AddOrGetExisting(string key, object value, DateTimeOffset absoluteExpiration, string regionName = null)
        {
            string fullKey = this.GetFullKey(key);
            return container.AddOrGetExisting(fullKey, value, absoluteExpiration, regionName);
        }

        public override bool Contains(string key, string regionName = null)
        {
            string fullKey = this.GetFullKey(key);
            return container.Contains(fullKey, regionName);
        }

        public override CacheEntryChangeMonitor CreateCacheEntryChangeMonitor(IEnumerable<string> keys, string regionName = null)
        {
            return container.CreateCacheEntryChangeMonitor(keys.Select(x => this.GetFullKey(x)), regionName);
        }

        public override DefaultCacheCapabilities DefaultCacheCapabilities
        {
            get { return container.DefaultCacheCapabilities; }
        }

        public override object Get(string key, string regionName = null)
        {
            string fullKey = this.GetFullKey(key);
            return container.Get(fullKey, regionName);
        }

        public override CacheItem GetCacheItem(string key, string regionName = null)
        {
            string fullKey = this.GetFullKey(key);
            CacheItem item = container.GetCacheItem(fullKey, regionName);
            if (item != null) { item = new CacheItem(this.GetOriginalKey(item.Key), item.Value, item.RegionName); }
            return item;
        }

        public override long GetCount(string regionName = null)
        {
            var prefix = this.GetFullKey(null);
            return container.Where(x => x.Key.StartsWith(prefix)).LongCount();
        }

        protected override IEnumerator<KeyValuePair<string, object>> GetEnumerator()
        {
            var prefix = this.GetFullKey(null);
            Dictionary<string, object> dict = new Dictionary<string, object>();
            foreach (var kv in container)
            {
                if (kv.Key.StartsWith(prefix))
                {
                    dict[this.GetOriginalKey(kv.Key)] = kv.Value;
                }
            }
            return dict.GetEnumerator();
        }

        public override IDictionary<string, object> GetValues(IEnumerable<string> keys, string regionName = null)
        {
            return container.GetValues(keys.Select(x => this.GetFullKey(x)), regionName);
        }

        public override string Name
        {
            get { return this.GetFullKey(null); }
        }

        public override object Remove(string key, string regionName = null)
        {
            string fullKey = this.GetFullKey(key);
            return container.Remove(fullKey, regionName);
        }

        public override void Set(string key, object value, CacheItemPolicy policy, string regionName = null)
        {
            string fullKey = this.GetFullKey(key);
            container.Set(fullKey, value, policy, regionName);
        }

        public override void Set(CacheItem item, CacheItemPolicy policy)
        {
            if (item != null)
            {
                item = new CacheItem(this.GetFullKey(item.Key), item.Value, item.RegionName);
            }
            container.Set(item, policy);
        }

        public override void Set(string key, object value, DateTimeOffset absoluteExpiration, string regionName = null)
        {
            string fullKey = this.GetFullKey(key);
            container.Set(fullKey, value, absoluteExpiration, regionName);
        }

        public override object this[string key]
        {
            get
            {
                string fullKey = this.GetFullKey(key);
                return container[fullKey];
            }
            set
            {
                string fullKey = this.GetFullKey(key);
                container[fullKey] = value;
            }
        }
    }
}
